package com.pi.shisan.util;

import static com.pi4j.wiringpi.Gpio.HIGH;
import static com.pi4j.wiringpi.Gpio.INPUT;
import static com.pi4j.wiringpi.Gpio.LOW;
import static com.pi4j.wiringpi.Gpio.OUTPUT;
import static com.pi4j.wiringpi.Gpio.digitalWrite;
import static com.pi4j.wiringpi.Gpio.pinMode;
import static com.pi4j.wiringpi.Gpio.wiringPiSetup;

//l  5 gnd 黑
//l  12  clk 褐色
//l  10  din 黄色
//r  13  cs  白色

/**
 * 脚编号使用wip
 * 使用直接操作，未使用提供的细化api
 * 全局仅一个对象，不可同时操作
 * max7219 单色8x8
 * （+ 红 ， GND 黑）
 * CLK - > SCLK bcm:11 wpi:14 board:23（褐）
 * DIN - > MOSI bcm:10 wpi:12 board:19 （橘）
 * CS -> CE1 bcm:7 wpi:11 board:26 （白）
 * 树莓派4b
 * 参阅com.shisan.pi.tools.PointToSPI，得到sendPoints方法参数
 * 非线程安全类
 *
 * 再说明：代码来自树莓派店家给的学习资料，原代码为python，基于 https://www.elecfans.com/d/1086616.html 提供的资料进行了改良
 * 因为pi4j的1.x版本与python的风格极为相似，所以较为容易的就迁移过来并测试通过，而pi4j的2.x版本的API风格已经改的亲妈都不认了，而且关于它的资料太少，仅官方文档给的极少的几个例子很难支撑我这种小白的需求，所以1.x还是比2.x香
 * */
public class Pi8x8Util {

    private static final int CS = 11, CLK = 14, DIN = 12;

    public static void writeData(long[] all) {
        int index = 0;
        byte[][] data = new byte[all.length][8];
        for (int i = 0; i < all.length; i++) {
            data[i] = DefaultFont8x8.getPoints(all[index]);
            index ++;
        }
        for (int j = 1; j <= 8; j++) {
            digitalWrite(CS, LOW);
            for (int i = 0; i < all.length; i++) {
                writeData(j, data[i][j - 1]);
            }
            digitalWrite(CS, HIGH);
        }
    }

    /**
     * 亮度调整，1 - 15
     * @param level
     */
    public static void setupLighter(int level, int size) {
        level &= 0xF;
        digitalWrite(CS, LOW);
        //亮度， 0x01 - 0x0F
        for (int i = 0; i < size; i++) {
            writeData(0x0a,level);
        }
        digitalWrite(CS, HIGH);
    }

    /**
     * 具体命令模式可参见
     * https://blog.csdn.net/qq_58006265/article/details/124903929
     * 这个博客写的相当清楚
     * @param size
     */
    public static void open(int size) {
        wiringPiSetup();
        pinMode(DIN,OUTPUT);
        pinMode(CS,OUTPUT);
        pinMode(CLK,OUTPUT);

        digitalWrite(CS, LOW);
        //不使用decode
        for (int i = 0; i < size; i++) {
            writeData(0x09,0x00);
        }
        digitalWrite(CS, HIGH);
        digitalWrite(CS, LOW);
        //亮度， 0x00 - 0x0F
        for (int i = 0; i < size; i++) {
            writeData(0x0a,0x01);
        }
        digitalWrite(CS, HIGH);
        digitalWrite(CS, LOW);
        //扫描8行（全部），可以选择扫描几行，0x0 - 0x7
        for (int i = 0; i < size; i++) {
            writeData(0x0b,0x07);
        }
        digitalWrite(CS, HIGH);
        digitalWrite(CS, LOW);
        //0x01 表示开机 0x00表示掉电
        for (int i = 0; i < size; i++) {
            writeData(0x0c,0x01);
        }
        digitalWrite(CS, HIGH);
        digitalWrite(CS, LOW);
        //0x0表示正常模式 0x1表示测试模式，你可以理解为屏幕坏点测试（所有点全亮）
        for (int i = 0; i < size; i++) {
            writeData(0xff,0x00);
        }
        digitalWrite(CS, HIGH);
    }

    public static void close(int size) {
        for (int i = 0; i < 8; i++) {
            digitalWrite(CS, LOW);
            for (int j = 0; j < size; j++) {
                writeData(j, 0x00);
            }
            digitalWrite(CS, HIGH);
        }
        digitalWrite(CS, LOW);
        for (int i = 0; i < size; i++) {
            writeData(0x0c,0x00);
        }
        digitalWrite(CS, HIGH);
        pinMode(DIN,INPUT);
        pinMode(CS,INPUT);
        pinMode(CLK,INPUT);
    }

    private static void writeData(int addr, int data) {
        writeByte(addr);
        writeByte(data);
    }

    private static void writeByte(int data) {
        for (int i = 0; i < 8; i++) {
            digitalWrite(CLK, LOW);
            digitalWrite(DIN, (data & 0x80) == 0 ? LOW : HIGH);
            digitalWrite(CLK, HIGH);
            data <<= 1;
        }
    }

}
